﻿/************************************************************************
 * author:漠然 2013年7月12日4:25:15
 * **********************************************************************/

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;

namespace Mrsoft.Common {
    public static class NativeMethods {
        public const int ProcessAllAccess = 0x1FFFFF;
        public const int ProcessVmWrite = 0x0020;
        public const int ProcessVmRead = 0x0010;
        public const int MemCommit = 0x1000;
        public const int PageExecuteReadwrite = 0x0040;
        //private const int PageReadwrite = 0x04;
        //private const int MemDecommit = 0x4000;
        public const int MemRelease = 0x8000;

        public const uint IFINITE = 0xFFFFFF;

        [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
        public static extern IntPtr GetModuleHandle(
            string lpModuleName);


        [DllImport("kernel32.dll")]
        public static extern IntPtr CreateRemoteThread(
            IntPtr hProcess,
            IntPtr lpThreadAttributes,
            IntPtr dwStackSize,
            IntPtr lpStartAddress,
            IntPtr lpParameter,
            uint dwCreationFlags,
            IntPtr lpThreadId);

        [DllImport("kernel32.dll", SetLastError = true)]
        public static extern bool CloseHandle(IntPtr hHandle);

        [DllImport("kernel32.dll")]
        public static extern IntPtr OpenProcess(
            Int32 dwDesiredAccess,
            [MarshalAs(UnmanagedType.Bool)] bool bInheritHandle,
            int dwProcessId);

        [DllImport("kernel32.dll", SetLastError = true)]
        public static extern IntPtr VirtualAllocEx(
            IntPtr hProcess,
            IntPtr lpAddress,
            IntPtr dwSize,
            Int32 flAllocationType,
            Int32 flProtect);

        [DllImport("kernel32.dll", SetLastError = true)]
        public static extern bool VirtualFreeEx(
            IntPtr hProcess,
            IntPtr lpAddress,
            IntPtr dwSize,
            Int32 dwFreeType);

        [DllImport("kernel32.dll", SetLastError = true)]
        public static extern bool WriteProcessMemory(
            IntPtr hProcess,
            IntPtr lpBaseAddress,
            byte[] lpBuffer,
            UIntPtr nSize,
            out UIntPtr lpNumberOfBytesWritten);


        [DllImport("kernel32.dll", SetLastError = true)]
        public static extern bool WriteProcessMemory(
            IntPtr hProcess,
            IntPtr lpBaseAddress,
            IntPtr lpBuffer,
            UIntPtr nSize,
            UIntPtr lpNumberOfBytesWritten);

        [DllImport("kernel32.dll", SetLastError = true)]
        public static extern bool ReadProcessMemory(
            IntPtr hProcess,
            IntPtr lpBaseAddress,
            out Int32 lpBuffer,
            IntPtr size,
            out IntPtr lpNumberOfBytesRead
            );

        [DllImport("kernel32.dll", SetLastError = true)]
        public static extern bool ReadProcessMemory(
            IntPtr hProcess,
            IntPtr lpBaseAddress,
            [Out] byte[] lpBuffer,
            IntPtr dwSize,
            out IntPtr lpNumberOfBytesRead
            );

        [DllImport("user32.dll")]
        public static extern bool FlashWindow(
            IntPtr hwnd,
            bool bInvert);

        [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Ansi)]
        public static extern bool SetWindowTextA(
            IntPtr hwnd,
            String lpString);

        [DllImport("kernel32.dll", SetLastError = true)]
        public static extern UInt32 WaitForSingleObject(
            IntPtr hHandle,
            UInt32 dwMilliseconds);

        [DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
        private static extern uint GetPrivateProfileString(
            string lpAppName,
            string lpKeyName,
            string lpDefault,
            StringBuilder lpReturnedString,
            uint nSize,
            string lpFileName);

        [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        private static extern bool WritePrivateProfileString(
            string lpAppName,
            string lpKeyName,
            string lpString,
            string lpFileName);

        [DllImport("kernel32.dll")]
        private static extern bool GetExitCodeThread(
            IntPtr hThread,
            out uint lpExitCode);

        [DllImport("kernel32.dll")]
        private static extern IntPtr LoadLibrary(string libFile);


        [DllImport("kernel32.dll", CharSet = CharSet.Ansi, SetLastError = true)]
        private static extern IntPtr GetProcAddress(IntPtr hModule, string functionName);

        [DllImport("kernel32.dll")]
        private static extern IntPtr FreeLibrary(IntPtr hModule);

        #region 用于实现单开显示
        [DllImport("user32.dll")]
        private static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
        [DllImport("user32.dll ", SetLastError = true)]
        private static extern void SwitchToThisWindow(IntPtr hWnd, bool fAltTab);
        [DllImport("user32.dll", EntryPoint = "ShowWindow", CharSet = CharSet.Auto)]
        private static extern int ShowWindow(IntPtr hwnd, int nCmdShow);
        private const int SwRestore = 9;
        public static void ShowStartedWindow(string windowTitle) {
            var theApp = Process.GetCurrentProcess();
            var allApp = Process.GetProcessesByName(theApp.ProcessName);
            var tem = allApp.Where(t => t.Id != theApp.Id);
            foreach (var t in tem) {
                if (t.MainWindowHandle == IntPtr.Zero) {
                    //如果找不到窗口hwnd
                    var formhwnd = FindWindow(null, windowTitle);
                    ShowWindow(formhwnd, SwRestore);
                    SwitchToThisWindow(formhwnd, true);
                }
                else {
                    //如果已经打开了就直接打开
                    SwitchToThisWindow(t.MainWindowHandle, true);
                }
            }
        }
        #endregion


        private delegate int DllRegisterServer();

        public static bool ComRegister(string comModulePath) {
            bool br = false;
            var hModule = LoadLibrary(comModulePath);
            if (hModule != IntPtr.Zero) {
                IntPtr pFunction = GetProcAddress(hModule, "DllRegisterServer");
                if (pFunction != IntPtr.Zero) {
                    var deFunc = (DllRegisterServer)Marshal.GetDelegateForFunctionPointer(pFunction, typeof(DllRegisterServer));
                    var result = deFunc();
                    if (result > 0)
                        br = true;
                }
                //FreeLibrary(hModule);
            }
            return br;
        }

        public static string IniReadValue(string filePath, string section, string key, string def = "") {
            var retVal = new StringBuilder(500);
            GetPrivateProfileString(section, key, def, retVal, 500, filePath);
            return retVal.ToString();
        }

        public static bool IniWriteValue(string filePath, string section, string key = "", string value = "") {
            return WritePrivateProfileString(section, key, value, filePath);
        }

        private static Dictionary<int, IntPtr> hProcessList = new Dictionary<int, IntPtr>();

        /// <summary>
        /// 获取指定进行的操作句柄
        /// </summary>
        /// <param name="dwProcessId">进程id</param>
        /// <param name="hProcess">成功返回操作句柄</param>
        /// <returns>返回是否获取到了</returns>
        private static bool GetProcessHandle(int dwProcessId, out IntPtr hProcess, int[] addArr, ref int addr) {
            //读取窗口操作的句柄
            if (!hProcessList.TryGetValue(dwProcessId, out hProcess)) {
                hProcess = OpenProcess(ProcessAllAccess, false, dwProcessId);
                if (hProcess == IntPtr.Zero) {
                    return false;
                }
                hProcessList.Add(dwProcessId, hProcess);
            }
            //读取初始化参数信息
            IntPtr iRead;
            for (int i = 0; i < addArr.Length - 1; i++) {
                if (!ReadProcessMemory(hProcess, (IntPtr)(addArr[i] + addr), out addr, (IntPtr)4, out iRead)) {
                    return false;
                }
            }
            return true;
        }

        public static string Rs(int dwProcessId, params int[] addArr) {
            IntPtr hProcess;
            int temAddr = 0;
            if (!GetProcessHandle(dwProcessId, out hProcess, addArr, ref temAddr)) {
                return string.Empty;
            }
            IntPtr iRead;
            var buffer = new byte[256];
            if (!ReadProcessMemory(hProcess, (IntPtr)(temAddr + addArr[addArr.Length - 1]), buffer, (IntPtr)buffer.Length, out iRead)) {
                return string.Empty;
            }
            for (temAddr = 0; temAddr < buffer.Length; temAddr++) {
                if (buffer[temAddr] == 0) {
                    break;
                }
            }
            var str = Encoding.Default.GetString(buffer, 0, temAddr);
            StringBuilder sb = new StringBuilder();
            foreach (var word in str) {
                if (word > 31) {
                    sb.Append(word);
                }
            }
            return sb.ToString();
        }

        public static int Ri(int dwProcessId, params int[] addArr) {
            IntPtr hProcess;
            int temAddr = 0;
            if (!GetProcessHandle(dwProcessId, out hProcess, addArr, ref temAddr)) {
                return -1;
            }
            IntPtr iRead;
            if (!ReadProcessMemory(hProcess, (IntPtr)(addArr[addArr.Length - 1] + temAddr), out temAddr, (IntPtr)4, out iRead)) {
                return -1;
            }
            return temAddr;
        }

        public static float Rf(int dwProcessId, params int[] addArr) {
            IntPtr hProcess;
            int temAddr = 0;
            if (!GetProcessHandle(dwProcessId, out hProcess, addArr, ref temAddr)) {
                return -1f;
            }
            IntPtr iRead;
            var buffer = new byte[4];
            if (!ReadProcessMemory(hProcess, (IntPtr)(temAddr + addArr[addArr.Length - 1]), buffer, (IntPtr)buffer.Length, out iRead)) {
                return -1f;
            }
            return BitConverter.ToSingle(buffer, 0);
        }

        public static byte Rb(int dwProcessId, params int[] addArr) {
            IntPtr hProcess;
            int temAddr = 0;
            if (!GetProcessHandle(dwProcessId, out hProcess, addArr, ref temAddr)) {
                return 0;
            }
            IntPtr iRead;
            var buffer = new byte[1];
            if (!ReadProcessMemory(hProcess, (IntPtr)(temAddr + addArr[addArr.Length - 1]), buffer, (IntPtr)buffer.Length, out iRead)) {
                return 0;
            }
            return buffer[0];
        }
    }
}
